#define RUNTIME_DBG_LVL			0
#include <dbg/ptest.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <metalc/base/mtls.h>
#include <metalc/mlos/brkheap.h>
#include <pthreadalt.h>

#include <unix/page_alloc_os.h>

#include "apds_common.h"


/* 定义mmap heap */
// DEF_MMAPHEAP_MLAYER(mmap_normal, 2 * 1024 * 1024, SIZE_1G, SIZE_64G, 1, 0)

/* 定义tlsf */
#include <metalc/mlayer/tlsf.h>
static tlsf_obj_t *ptlsf;
DEF_TLSF_MLAYER(tlsf, ptlsf, 4, MLAYER_SZ_MAXBIT, 4 * SIZE_1G, 5, page_alloc)

/* 组合 */
COMPOSE_MLAYER(test_tlsf, tlsf, brkheap)

/* 定义tls */
DEF_MTLS_PTHREAD(GET_MLAYER_OBJNR(test_tlsf), 4096, mlcc_palloc, mp_coreid)

/* 定义初始化过程 */
#include <pthreadalt/pthreadalt_init.h>
DEF_PTHREADALT_INIT
DEF_SYSINIT(mtls, testnode, test_tlsf)
DEF_CFLOWFIN(mtls)
DEF_CFLOWINIT(mtls, test_tlsf)
DEF_SYSFIN(__omega)

/* 测试 */

#define TEST_MAXTHREADS	(24)
#define TEST_NR		(1000000)

#define TEST_MINSIZE	(16)
#define TEST_MAXSIZE	(256)
#define TEST_SET	(0)
#define TEST_ALLOC	test_tlsf_alloc
#define TEST_FREE	test_tlsf_free
#define TEST_SIZEOF	test_tlsf_sizeof
// static void *bench_tlsf(void *args){
// 	PARAM_USED(args);
// 	mreq_t req;
// 	for (word_t idx = 0; idx < TEST_NR; idx++){
// 		size_t rqsize = TEST_MINSIZE + hash(idx + rdcnt_relax()) % (TEST_MAXSIZE - TEST_MINSIZE);
// 		mreq_setalloc(&req, rqsize, 0);
		
// 		void *mem = TEST_ALLOC(&req);
// 		assert(mem);
		
// 		uvoid *umem = req.ptr;
// 		assert(umem);
// 		PARAM_USED(umem);
// 		assert(umem - mem == sizeof(cobj_t));
// 		size_t size = TEST_SIZEOF(&req);
// 		assert(size >= rqsize);
		
// 		size_t usize = req.usize;
// 		assert(usize >= rqsize);
// 		assert(size - usize == sizeof(cobj_t));
// 		assert(req.ptr == mem);
// 		req.size = size;
		
// 		if (TEST_SET) {
// 			__memset(umem, 0xff, rqsize);
// 			INFO("memset [%p - %p]\n", umem, umem + usize);
// 		}
// 		/* printf("[set %lx]") */
// 		bool_t s = TEST_FREE(&req);
// 		assert(s == TRUE);
// 	}
// 	return NULL;
// }

static void *bench_tlsf(void *args){
	PARAM_USED(args);
	mreq_t req;
	for (word_t idx = 0; idx < TEST_NR; idx++){
		size_t rqsize = TEST_MINSIZE + hash(idx + rdcnt_relax()) % (TEST_MAXSIZE - TEST_MINSIZE);
		mreq_setalloc(&req, rqsize, 0);
		uvoid *umem = TEST_ALLOC(&req);
		void *mem = req.ptr;
		// assert(umem);
		req.ptr = umem;
		size_t size = TEST_SIZEOF(&req);
		PARAM_USED(umem, mem, size);
		if (TEST_SET) {
			__memset(umem, 0xff, rqsize);
			// INFO("memset [%p - %p]\n", umem, umem + usize);
		}
		TEST_FREE(&req);
	}
	return NULL;
}
PERF_PARALLEL_FUNC_THREADNR(bench_tlsf, TEST_NR * 2, TEST_MAXTHREADS)

void test_tlsf_basic(){
	mreq_t req;
	void *mem;
	mreq_setalloc(&req, 4096, 4096);
	mem = test_tlsf_alloc(&req);
	assert(mem == req.ptr + sizeof(cobj_t));
	// assert(mem);
	// assert(req.size == SIZE_2M); /* 等于对齐大小 */
	ASSERT(mem);
	memset(mem, 0xff, 4096);
	// word_t *parr = (word_t *)mem;
	// assert(atm_ld(&(parr[256])) == (word_t)(-1));
	req.ptr = mem;
	size_t sz = test_tlsf_sizeof(&req);
	assert(sz >= 0x1000);
	assert(req.size - sz == sizeof(cobj_t));
	// assert(sz = 0x1000 );
	// req.size = sz;
	// assert(req.ptr == mem);
	bool_t s = test_tlsf_free(&req);
	assert(s == TRUE);


	// void *mem2, *mem3;
	// mreq_setalloc(&req, 65536*2, 65536);
	// mem = test_tlsf_alloc(&req);

	// mreq_setalloc(&req, 65536, 65536);
	// mem2 = test_tlsf_alloc(&req);

	// mreq_setalloc(&req, 65536*2, 65536);
	// mem3 = test_tlsf_alloc(&req);

	// req.ptr = mem2;
	// test_tlsf_sizeof(&req);
	// assert(req.size == 0x10000);
	// s = test_tlsf_free(&req);
	// assert(s == TRUE);

	// req.ptr = mem;
	// test_tlsf_sizeof(&req);
	// assert(req.size == 0x20000);
	// s = test_tlsf_free(&req);
	// assert(s == TRUE);

	// req.ptr = mem3;
	// test_tlsf_sizeof(&req);
	// assert(req.size == 0x20000);
	// s = test_tlsf_free(&req);
	// assert(s == TRUE);
}
static void test_tlsf_end(){
	dbg_printf("tlsf bench ok\n");
}
/* perf测试 */
int main(){
	test_tlsf_basic();
	dbg_printf("now bench tlsf\n");
	PERF_PARALLEL_RUN(bench_tlsf);
	test_tlsf_end();
	return 0;
}